#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/poll.h>

#include <unistd.h>

int main(int argc, char **argv)
{
    int socket_fd;
    struct sockaddr_in servaddr;
    struct pollfd fds[128];
    memset(fds, 0, sizeof(fds)); // 重中之重, 初始化, 预防垃圾值

    // 初始化Socket
    if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
        exit(0);
    }

    // 初始化
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = INADDR_ANY;
    servaddr.sin_port = htons(8080);

    // 将本地地址绑定到所创建的套接字上
    if (bind(socket_fd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
    {
        printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno);
        exit(0);
    }

    // 开始监听是否有客户端连接
    if (listen(socket_fd, 10) == -1)
    {
        printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);
        exit(0);
    }

    printf("listen \n");

    // 客户端套接字

    int min_fd = socket_fd;

    fds[0].fd = socket_fd;
    fds[0].events = POLLIN | POLLOUT;

    printf("min_fd: %d\n", min_fd);

    int max_fd = socket_fd - min_fd;

    while (1)
    {
        // printf("poll wait......\n");
        int nReady = poll(fds, 128, -1); // -1无限等待, 阻塞
        // printf("nReady: %d\n", nReady);
        if (nReady > 0)
        {
            short main_mask = fds[0].revents;
            // printf("main mask: %d\n", main_mask);

            // 处理 svrFd, 一般是 cli 有连接产生
            if (main_mask & POLLIN)
            {
                // printf("===receive a connetction====\n");
                int svrFd = fds[0].fd;
                int cliFd;

                if ((cliFd = accept(svrFd, NULL, NULL)) == -1)
                {
                    printf("accept socket error: %s(errno: %d)", strerror(errno), errno);
                }
                else
                {
                    printf("new client:[%d]\n", cliFd);
                }

                fds[cliFd].fd = cliFd;
                fds[cliFd].events = POLLIN | POLLOUT | POLLRDHUP;
            }

            // 遍历处理所有的客户端套接字
            for (int i = 4; i < 128; ++i)
            {
                short mask = fds[i].revents;
                // printf("mask: %d\n", mask);
                if (mask & (POLLIN))
                {
                    char rBuff[128] = {0};
                    char wBuff[128] = {0};

                    int rSize = recv(fds[i].fd, &rBuff, sizeof(rBuff), 0);

                    // 获取数据之后, 看选择性删除该套接字
                    if (rSize <= 0)
                    {
                        // perror("read() failed");
                        // exit(EXIT_FAILURE);
                        printf("Connection closed from socket %d\n", fds[i].fd);
                        close(fds[i].fd);
                        continue;
                    }
                    else if (rSize > 0)
                    {
                        printf("Read:%s\n", rBuff);
                    }
                    strcpy(wBuff, "pong");
                    // 发送数据给客户端
                    // write(cliFd, buff, sizeof(buff));
                    int wSize = send(fds[i].fd, wBuff, sizeof(wBuff), 0);
                    // wSize返回值同 rSize
                }
                if (mask & POLLRDHUP)
                {
                    // printf("err event\n");
                    fds[i].fd = 0;
                    fds[i].events = 0;
                }
            }
        }
        else if (nReady == 0)
        {
            printf("Poll Nothing\n");
        }
        else
        {
            printf("Poll error\n");
        }

        // usleep(1000 * 10);
    }

    close(socket_fd);
}
